package com.atguigu.tingshu.search.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.LongTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import co.elastic.clients.json.JsonData;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategory3;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumInfoIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestWordRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumInfoIndexRepository albumInfoIndexRepository;
    @Autowired
    private AlbumFeignClient albumFeignClient;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private SuggestWordRepository suggestWordRepository;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void upperAlbum(Long albumId) {
        AlbumInfoIndex  albumInfoIndex = new AlbumInfoIndex();

            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfo, "获取" + albumInfo.getId() + "失败");
            //功能：从数据库中关于专辑的数据信息上传到es中 上传数据的实体对象为AlbumInfoIndex
            BeanUtil.copyProperties(albumInfo, albumInfoIndex);

        //需要获取专辑的基本数据信息
//        albumInfoIndex.setId(albumId);

            //专辑标签数据需要处理为AttributeValueIndex

            List<AttributeValueIndex> valueIndexList = new ArrayList<>();
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            if(albumAttributeValueVoList!=null){
                for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
                    AttributeValueIndex attributeValueIndex = BeanUtil.copyProperties(albumAttributeValue, AttributeValueIndex.class);
                    valueIndexList.add(attributeValueIndex);
                }
            }
            HashMap<String, String> map = new HashMap<>();

            albumInfoIndex.setAttributeValueIndexList(valueIndexList);




            //.封装分类信息 从专辑信息中获取到的三级分类id 但还是需要1 2级分类ID
            BaseCategoryView baseCategoryView = albumFeignClient.getCategoryViewBy3Id(albumInfo.getCategory3Id()).getData();
            Assert.notNull(baseCategoryView, "获取三级分类数据失败");
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
            //关于主播信息也需要进行封装




            //关于主播信息也需要进行封装
            Long userId = albumInfo.getUserId();
            UserInfoVo userInfoVo = userFeignClient.getUserVoById(userId).getData();
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());


            //5.TODO 封装统计信息，采用产生随机值 以及专辑热度
            //5.1 随机为专辑产生播放量，订阅量，购买量，评论量 、
        AlbumStatVo albumStatVo = albumFeignClient.getAlbumStatVo(albumId).getData();
        int num1 = RandomUtil.randomInt(1000, 2000);
            int num2 = RandomUtil.randomInt(500, 1000);
            int num3 = RandomUtil.randomInt(200, 400);
            int num4 = RandomUtil.randomInt(100, 200);
            albumInfoIndex.setPlayStatNum(num1);
            albumInfoIndex.setSubscribeStatNum(num2);
            albumInfoIndex.setBuyStatNum(num3);
            albumInfoIndex.setCommentStatNum(num4);

            //5.2 基于统计值计算出专辑得分 为不同统计类型设置不同权重
            BigDecimal bigDecimal1 = new BigDecimal(num4).multiply(new BigDecimal("0.4"));
            BigDecimal bigDecimal2 = new BigDecimal(num3).multiply(new BigDecimal("0.3"));
            BigDecimal bigDecimal3 = new BigDecimal(num2).multiply(new BigDecimal("0.2"));
            BigDecimal bigDecimal4 = new BigDecimal(num1).multiply(new BigDecimal("0.1"));
            BigDecimal hotScore = bigDecimal1.add(bigDecimal2).add(bigDecimal3).add(bigDecimal4);
            albumInfoIndex.setHotScore(hotScore.doubleValue());


        //6.将索引库文档对象存入索引库
        albumInfoIndexRepository.save(albumInfoIndex);
//        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("albumItemBloom");
//        bloomFilter.tryInit(100000L,0.01);
        redissonClient.getBloomFilter("albumItemBloom").add(albumId);
        this.upperSuggest(albumId,albumInfoIndex.getAlbumTitle());
//        AlbumInfoIndex  albumInfoIndex = new AlbumInfoIndex();
//        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
//            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
//            Assert.notNull(albumInfo, "获取" + albumInfo.getId() + "失败");
//            //功能：从数据库中关于专辑的数据信息上传到es中 上传数据的实体对象为AlbumInfoIndex
//            BeanUtil.copyProperties(albumInfo, albumInfoIndex);
//            return albumInfo;
//        }, threadPoolExecutor);
//        //需要获取专辑的基本数据信息
////        albumInfoIndex.setId(albumId);
//        CompletableFuture<Void> albumAttributeValueCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
//            //专辑标签数据需要处理为AttributeValueIndex
//
//            List<AttributeValueIndex> valueIndexList = new ArrayList<>();
//            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
//            if(albumAttributeValueVoList!=null){
//                for (AlbumAttributeValue albumAttributeValue : albumAttributeValueVoList) {
//                    AttributeValueIndex attributeValueIndex = BeanUtil.copyProperties(albumAttributeValue, AttributeValueIndex.class);
//                    valueIndexList.add(attributeValueIndex);
//                }
//            }
//            HashMap<String, String> map = new HashMap<>();
//
//            albumInfoIndex.setAttributeValueIndexList(valueIndexList);
//        }, threadPoolExecutor);
//
//
//        CompletableFuture<Void> baseCategoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
//            //.封装分类信息 从专辑信息中获取到的三级分类id 但还是需要1 2级分类ID
//            BaseCategoryView baseCategoryView = albumFeignClient.getCategoryViewBy3Id(albumInfo.getCategory3Id()).getData();
//            Assert.notNull(baseCategoryView, "获取三级分类数据失败");
//            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
//            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
//            //关于主播信息也需要进行封装
//        }, threadPoolExecutor);
//
//        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
//
//            //关于主播信息也需要进行封装
//            Long userId = albumInfo.getUserId();
//            UserInfoVo userInfoVo = userFeignClient.getUserVoById(userId).getData();
//            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
//        }, threadPoolExecutor);
//        CompletableFuture<Void> hotScoreCompletableFuture = CompletableFuture.runAsync(() -> {
//            //5.TODO 封装统计信息，采用产生随机值 以及专辑热度
//            //5.1 随机为专辑产生播放量，订阅量，购买量，评论量 、
//            int num1 = RandomUtil.randomInt(1000, 2000);
//            int num2 = RandomUtil.randomInt(500, 1000);
//            int num3 = RandomUtil.randomInt(200, 400);
//            int num4 = RandomUtil.randomInt(100, 200);
//            albumInfoIndex.setPlayStatNum(num1);
//            albumInfoIndex.setSubscribeStatNum(num2);
//            albumInfoIndex.setBuyStatNum(num3);
//            albumInfoIndex.setCommentStatNum(num4);
//
//            //5.2 基于统计值计算出专辑得分 为不同统计类型设置不同权重
//            BigDecimal bigDecimal1 = new BigDecimal(num4).multiply(new BigDecimal("0.4"));
//            BigDecimal bigDecimal2 = new BigDecimal(num3).multiply(new BigDecimal("0.3"));
//            BigDecimal bigDecimal3 = new BigDecimal(num2).multiply(new BigDecimal("0.2"));
//            BigDecimal bigDecimal4 = new BigDecimal(num1).multiply(new BigDecimal("0.1"));
//            BigDecimal hotScore = bigDecimal1.add(bigDecimal2).add(bigDecimal3).add(bigDecimal4);
//            albumInfoIndex.setHotScore(hotScore.doubleValue());
//        }, threadPoolExecutor);
//        CompletableFuture.allOf(albumInfoCompletableFuture,albumAttributeValueCompletableFuture,
//                userCompletableFuture,hotScoreCompletableFuture,baseCategoryCompletableFuture).join();
//        //6.将索引库文档对象存入索引库
//        albumInfoIndexRepository.save(albumInfoIndex);
////        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("albumItemBloom");
////        bloomFilter.tryInit(100000L,0.01);
//        redissonClient.getBloomFilter("albumItemBloom").add(albumId);
//        this.upperSuggest(albumId,albumInfoIndex.getAlbumTitle());
    }

    private void upperSuggest(Long albumId, String albumTitle) {
        SuggestIndex suggestIndex = new SuggestIndex();
        suggestIndex.setId(albumTitle);
        suggestIndex.setTitle(albumTitle);
        suggestIndex.setKeyword(new Completion(new String[]{albumTitle}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinyinUtil.getPinyin(albumTitle,"")}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinyinUtil.getFirstLetter(albumTitle,"")}));
        suggestWordRepository.save(suggestIndex);
    }

    @Override
    public AlbumInfoIndex getAlbumInfoIndex(Long id){
        Optional<AlbumInfoIndex> optional = albumInfoIndexRepository.findById(id);

        System.out.println(optional);
        AlbumInfoIndex albumInfoIndex = optional.get();
        return albumInfoIndex;
    }

    @Override
    public void lowerAlbum(Long albumId) {
        albumInfoIndexRepository.deleteById(albumId);
    }

    @Override
    @SneakyThrows
    @GuiGuCache(prefix = "albumSearchResponseVo:")
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        System.out.println(albumIndexQuery);
        //设置查询条件
        SearchRequest.Builder builder = new SearchRequest.Builder();
        //设置操作的索引库
        builder.index("albuminfo");
        BoolQuery.Builder allBuilder = new BoolQuery.Builder();
        //根据关键字匹配专辑标题、简介、作者名称信息
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())){
            BoolQuery.Builder keyWordBuilder = new BoolQuery.Builder();
            keyWordBuilder.should(s->s.match(m->m.field("albumTitle").query(albumIndexQuery.getKeyword())));
            keyWordBuilder.should(s->s.match(m->m.field("albumIntro").query(albumIndexQuery.getKeyword())));
            keyWordBuilder.should(s->s.term(m->m.field("announcerName").value(albumIndexQuery.getKeyword())));
            allBuilder.must(b->b.bool(keyWordBuilder.build()));
        }
        //根据分类ID匹配专辑数据
        if (albumIndexQuery.getCategory1Id()!=null){
            allBuilder.filter(f->f.term(t->t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }
        if (albumIndexQuery.getCategory2Id()!=null){
            allBuilder.filter(f->f.term(t->t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (albumIndexQuery.getCategory3Id()!=null){
            allBuilder.filter(f->f.term(t->t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        //根据标签属性进行参数的添加 由于前端传来的参数为 属性id:属性值id 需要进行处理
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (attributeList!=null){
            for (String  attribute : attributeList) {
                String[] split = attribute.split(":");
                allBuilder.filter(f->f.nested(n->n.path("attributeValueIndexList").query(q->q.term(t->t.field("attributeValueIndexList.attributeId").value(split[0])))
                        .query(q->q.term(t->t.field("attributeValueIndexList.valueId").value(split[1])))
                ));
            }
        }
        //排序 由于前端传递参数为综合排序[1:desc] 所以需要拆分 然后拿到对应数据进行填充
        String order = albumIndexQuery.getOrder();
        //4.2 按照冒号对查询条件进行分割得到数组
        if (StringUtils.isNotBlank(order)) {
            //4.2 按照冒号对查询条件进行分割得到数组
            String[] split = order.split(":");
            if (split != null && split.length == 2) {
                //4.3 判断得到排序字段
                String orderField = "";
                switch (split[0]) {
                    case "1":
                        orderField = "hotScore";
                        break;
                    case "2":
                        orderField = "playStatNum";
                        break;
                    case "3":
                        orderField = "createTime";
                        break;
                }
                //4.4 设置排序
                String finalOrderField = orderField;
                builder.sort(s -> s.field(f -> f.field(finalOrderField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }
        //分页参数填充
        builder.size(albumIndexQuery.getPageSize());
        builder.from((albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize());
        builder.highlight(h->h.fields("albumTitle",t->t.preTags("<font style='color:red'>").postTags("</font>")));
        builder.source(s->s.filter(f->f.excludes("category1Id",
                "category2Id",
                "category3Id",
                "attributeValueIndexList.attributeId",
                "attributeValueIndexList.valueId")));
        builder.query(allBuilder.build()._toQuery());
        System.out.println("开始执行");
        SearchResponse<AlbumInfoIndex> response = elasticsearchClient.search(builder.build(), AlbumInfoIndex.class);
        System.out.println(response);
        List<Hit<AlbumInfoIndex>> hits = response.hits().hits();
        for (Hit<AlbumInfoIndex> hit : hits) {
            System.out.println(hit.source());
        }
        //1.构建响应VO对象
        AlbumSearchResponseVo vo = new AlbumSearchResponseVo();
        //2.封装分页信息（总记录数、总页数、页码、页大小）
        vo.setPageNo(albumIndexQuery.getPageNo());
        Integer pageSize = albumIndexQuery.getPageSize();
        vo.setPageSize(pageSize);
        //1.1 从ES响应结果中得到总记录数
        long total = response.hits().total().value();
        vo.setTotal(total);
        //1.2 动态计算总页数
        long totalPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
        vo.setTotalPages(totalPages);
        //3.封装检索到业务数据（专辑搜索Vo集合）
        List<Hit<AlbumInfoIndex>> hitList = response.hits().hits();
        if (CollectionUtil.isNotEmpty(hitList)) {
            List<AlbumInfoIndexVo> infoIndexVoList = hitList.stream().map(hit -> {
                //将获取到的文档对象AlbumInfoIndex类型转为AlbumInfoIndexVo类型
                AlbumInfoIndexVo albumInfoIndexVo = BeanUtil.copyProperties(hit.source(), AlbumInfoIndexVo.class);
                //处理高亮片段
                Map<String, List<String>> highlightMap = hit.highlight();
                if(CollectionUtil.isNotEmpty(highlightMap) && highlightMap.containsKey("albumTitle")){
                    String highlightAlbumTitle = highlightMap.get("albumTitle").get(0);
                    albumInfoIndexVo.setAlbumTitle(highlightAlbumTitle);
                }
                return albumInfoIndexVo;
            }).collect(Collectors.toList());
            vo.setList(infoIndexVoList);
        }

        return vo;
    }

    @Override
    @SneakyThrows
    public List<Map<String, Object>> getTopCategory3HotAlbumList(Long category1Id) {
        //获取对应一级分类下top7的三级分类ID 首页数据需要top数据 根据这些ID去查询对应三级分类ID下的6个数据
        List<BaseCategory3> category3List = albumFeignClient.findTopBaseCategory3(category1Id).getData();
        Assert.notNull(category3List,"获取三级ID数据失败");
        List<FieldValue> category3Ids = category3List.stream().map(baseCategory3 -> {
            return FieldValue.of(baseCategory3.getId());
        }).collect(Collectors.toList());
        Map<Long, BaseCategory3> category3Map = category3List.stream()
                .collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        SearchRequest.Builder builder = new SearchRequest.Builder();
        for (FieldValue category3Id : category3Ids) {
            builder.query(q->q.terms(t->t.field("category3Id").terms(e->e.value(category3Ids))));
        }
        builder.size(0);
        builder.aggregations("category3IdAgg",agg->
                agg.terms(t->
                        t.field("category3Id").size(10)).aggregations("top6Agg",tagg->tagg.topHits(h->h.size(6).sort(s->s.field(f->f.field("hotScore").order(SortOrder.Desc))))));

        SearchResponse<AlbumInfoIndex> search = elasticsearchClient.search(builder.build(), AlbumInfoIndex.class);
        Map<String, Aggregate> aggregations = search.aggregations();
        Buckets<LongTermsBucket> category3IdAgg = aggregations.get("category3IdAgg").lterms().buckets();
        List<LongTermsBucket> array = category3IdAgg.array();
        //3.3 遍历“桶”集合，每遍历一个“桶”处理某个置顶三级分类热门专辑
        List<Map<String, Object>> listMap = array.stream().map(bucket -> {
            Map<String, Object> map = new HashMap<>();
            //3.3.1 处理热门专辑->分类
            long category3Id = bucket.key();
            BaseCategory3 baseCategory3 = category3Map.get(category3Id);
            map.put("baseCategory3", baseCategory3);
            //3.3.2 处理热门专辑->专辑列表
            //3.3.2.1 继续下钻获取子聚合得到当前分类下热门专辑
            Aggregate top6Agg = bucket.aggregations().get("top6Agg");
            List<Hit<JsonData>> hits = top6Agg.topHits().hits().hits();
            if (CollectionUtil.isNotEmpty(hits)) {
                List<AlbumInfoIndex> hotAlbumList = hits.stream().map(hit -> {
                    //获取专辑JSON对象类型
                    JsonData source = hit.source();
                    return JSON.parseObject(source.toString(), AlbumInfoIndex.class);
                }).collect(Collectors.toList());
                map.put("list", hotAlbumList);
            }
            return map;
        }).collect(Collectors.toList());


        return listMap;
    }

    @Override
    @GuiGuCache(prefix = "albumItem:")
    public Map<String, Object> albumItem(Long albumId) {
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("albumItemBloom");
        boolean contains = bloomFilter.contains(albumId);
        if (!contains){
            return new HashMap<>();
        }
        Map<String,Object> map = new HashMap<>();
        //获取专辑详情信息 专辑信息 作者信息 统计信息 分类信息
        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
            Assert.notNull(albumInfo, "获取专辑信息失败");
            map.put("albumInfo", albumInfo);
            return albumInfo;
        }, threadPoolExecutor);
        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            UserInfoVo user = userFeignClient.getUserVoById(albumInfo.getUserId()).getData();
            Assert.notNull(user, "获取作者信息失败");
            map.put("announcer", user);
        }, threadPoolExecutor);

        CompletableFuture<Void> statVoCompletableFuture = CompletableFuture.runAsync(() -> {
            AlbumStatVo statVo = albumFeignClient.getAlbumStatVo(albumId).getData();
            Assert.notNull(statVo, "获取统计信息失败");
            map.put("albumStatVo", statVo);
        }, threadPoolExecutor);

        CompletableFuture<Void> categoryViewCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            BaseCategoryView categoryView = albumFeignClient.getCategoryViewBy3Id(albumInfo.getCategory3Id()).getData();
            Assert.notNull(categoryView, "获取分类信息失败");
            map.put("baseCategoryView", categoryView);
        }, threadPoolExecutor);
        CompletableFuture.allOf(albumInfoCompletableFuture,userCompletableFuture,statVoCompletableFuture,categoryViewCompletableFuture).join();

        return map;
    }

    @Override
    @SneakyThrows
    public List<String> completeSuggest(String keyword) {
        //关键字补全
        //根据keywoed去查询索引库中 进行三种方式匹配 匹配到的多个专辑标题按照数组的方式返回前端\
        //拿到数据需要放入数组中 但是多个匹配方法会导致数据重复 所以需要进行去重 而具有去重和数组的功能可以通过set函数进行封装
        Set<String> set = new HashSet<>();

        SearchResponse<SuggestIndex> search = elasticsearchClient.search(i -> i.index("suggestinfo")
                .suggest(s -> s.suggesters("keywordSuggester", su -> su.prefix(keyword).completion(c -> c.field("keyword").fuzzy(fu -> fu.fuzziness("auto")))))
                .suggest(s -> s.suggesters("pinyinSuggester", su -> su.prefix(keyword).completion(c -> c.field("keywordPinyin").fuzzy(fu -> fu.fuzziness("auto")))))
                .suggest(s -> s.suggesters("letterSuggester", su -> su.prefix(keyword).completion(c -> c.field("keywordSequence").fuzzy(fu -> fu.fuzziness("auto")))))
                , SuggestIndex.class);
        
        parseSuggest(set,"letterSuggester",search.suggest());
        parseSuggest(set,"letterSuggester",search.suggest());
        parseSuggest(set,"letterSuggester",search.suggest());
        if (set.size()>=10){
            return new ArrayList<>(set).subList(0,10);
        }
        else {
            SearchResponse<AlbumInfoIndex> albumSearch = elasticsearchClient.search(s -> s.index("albuminfo")
                    .query(q -> q.match(m -> m.query(keyword).field("albumTitle"))), AlbumInfoIndex.class);
            List<Hit<AlbumInfoIndex>> hits = albumSearch.hits().hits();
            if (hits != null) {
                for (Hit<AlbumInfoIndex> hit : hits) {
                    AlbumInfoIndex source = hit.source();
                    set.add(source.getAlbumTitle());
                    if (set.size()>=10){
                        return new ArrayList<>(set);
                    }
                }
            }


        }


        return new ArrayList<>(set);
    }

    @Override
    @SneakyThrows
    public void updateLatelyAlbumRanking() {
        //根据一级分类ID和排序方式获取对应的专辑列表 10个
        //3.1 声明排序方式数组
        String[] rankingDimensionArray =
                new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
        List<Long> category1Ids = albumFeignClient.getAllCategory1().getData();
        Assert.notNull(category1Ids,"获取一级分类ID失败");
        for (Long category1Id : category1Ids) {
            for (String order : rankingDimensionArray) {
                SearchResponse<AlbumInfoIndex> search = elasticsearchClient.search(s -> s.index("albuminfo")
                        .query(q->q.term(t->t.field("category1Id").value(category1Id)))
                        .size(10).sort(so -> so.field(f -> f.field(order).order(SortOrder.Desc))), AlbumInfoIndex.class);
                List<AlbumInfoIndex> list = search.hits().hits().stream().map(albumInfoIndexHit -> albumInfoIndexHit.source()).collect(Collectors.toList());
                //4.将榜单专辑列表存入Redis-Hash中
                //4.1 声明Redis排行榜Hash接口 Key 形式：前缀+1级分类ID     field：排序方式  val:榜单列表
                String key = RedisConstant.RANKING_KEY_PREFIX + category1Id;
                //4.2 将当前分类榜单数据放入Redis中
                redisTemplate.opsForHash().put(key, order, list);

            }
        }
    }

    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String dimension) {
        String key = RedisConstant.RANKING_KEY_PREFIX + category1Id;
        List<AlbumInfoIndex> object = (List<AlbumInfoIndex>)redisTemplate.opsForHash().get(key, dimension);
        Assert.notNull(object);
        System.out.println(object);
        return object;
    }

    private void parseSuggest(Set<String> set, String suggester, Map<String, List<Suggestion<SuggestIndex>>> suggest) {
        List<Suggestion<SuggestIndex>> suggestions = suggest.get(suggester);
        if (suggestions!= null){
            for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestions) {
                for (CompletionSuggestOption<SuggestIndex> option : suggestIndexSuggestion.completion().options()) {

                    set.add(option.source().getTitle());
                }
            }
        }


    }

}
